use super::define;
use super::errors::PackerError;
use super::errors::UnPackerError;
use super::RtpPacket;
use async_trait::async_trait;
use bytes::BytesMut;
use bytesio::bytes_reader::BytesReader;
use bytesio::bytesio::TNetIO;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::time::SystemTime;
use streamhub::define::FrameData;
use tokio::sync::Mutex;

pub trait Unmarshal<T1, T2> {
    fn unmarshal(data: T1) -> T2
    where
        Self: Sized;
}

pub trait Marshal<T> {
    fn marshal(&self) -> T;
}

pub type OnFrameFn = Box<dyn Fn(FrameData) -> Result<(), UnPackerError> + Send + Sync>;

pub type OnRtpPacketFn = Box<
    dyn Fn(
            Arc<Mutex<Box<dyn TNetIO + Send + Sync>>>,
            RtpPacket,
        ) -> Pin<Box<dyn Future<Output = Result<(), PackerError>> + Send + 'static>>
        + Send
        + Sync,
>;

pub type OnRtpPacketFn2 =
    Box<dyn Fn(RtpPacket) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> + Send + Sync>;

// 处理 RTCP（实时传输控制协议）相关的 RTP 数据包
pub trait TRtpReceiverForRtcp {
    fn on_packet_for_rtcp_handler(&mut self, f: OnRtpPacketFn2);
}

// 用于进行 RTP 打包操作。
#[async_trait]
pub trait TPacker: TRtpReceiverForRtcp + Send + Sync {
    // 将 NALU（网络抽象层单元）数据分割成 RTP 数据包并发送出去
    async fn pack(&mut self, nalus: &mut BytesMut, timestamp: u32) -> Result<(), PackerError>;
    // 方法 on_packet_handler，用于设置处理 RTP 数据包的闭包。
    fn on_packet_handler(&mut self, f: OnRtpPacketFn);
}

// 用于视频数据的 RTP 打包操作。
#[async_trait]
pub trait TVideoPacker: TPacker {
    // 将单个 NALU 打包成 RTP 数据包。
    async fn pack_nalu(&mut self, nalu: BytesMut) -> Result<(), PackerError>;
}

/// 用于进行 RTP 解包操作
#[async_trait]
pub trait TUnPacker: TRtpReceiverForRtcp + Send + Sync {
    // 将 RTP 片段组装成完整的帧并发送到流中心
    async fn unpack(&mut self, reader: &mut BytesReader) -> Result<(), UnPackerError>;
    // 方法 on_frame_handler，用于设置处理帧数据的闭包
    fn on_frame_handler(&mut self, f: OnFrameFn);
}

// 判断 FU（分片单元）头是否表示分片的开始。
pub(super) fn is_fu_start(fu_header: u8) -> bool {
    fu_header & define::FU_START > 0
}

// 判断 FU（分片单元）头是否表示分片的结束
pub(super) fn is_fu_end(fu_header: u8) -> bool {
    fu_header & define::FU_END > 0
}

// 函数用于在 NALU 数据中查找起始码（0x00 0x00 0x01）的位置
pub fn find_start_code(nalus: &[u8]) -> Option<usize> {
    let pattern = [0x00, 0x00, 0x01];
    nalus.windows(pattern.len()).position(|w| w == pattern)
}

// 将 Annex-B 格式的 NALU 数据分割并处理
pub async fn split_annexb_and_process<T: TVideoPacker>(
    nalus: &mut BytesMut,
    packer: &mut T,
) -> Result<(), PackerError> {
    while !nalus.is_empty() {
        // 在 NALU 数据中查找第一个起始码的位置
        if let Some(first_pos) = find_start_code(&nalus[..]) {
            // 查找下一个起始码的位置，以确定一个完整 NALU 的范围
            let mut nalu_with_start_code =
                if let Some(distance_to_first_pos) = find_start_code(&nalus[first_pos + 3..]) {
                    let mut second_pos = first_pos + 3 + distance_to_first_pos;
                    // 处理起始码前可能存在的额外 0 字节
                    while second_pos > 0 && nalus[second_pos - 1] == 0 {
                        second_pos -= 1;
                    }
                    // 从字节缓冲区中分割出包含起始码的 NALU
                    nalus.split_to(second_pos)
                } else {
                    // 如果没有找到下一个起始码，将剩余的所有数据作为一个 NALU
                    nalus.split_to(nalus.len())
                };

            // 从包含起始码的 NALU 中分割出真正的 NALU 数据（去除起始码）
            let nalu = nalu_with_start_code.split_off(first_pos + 3);
            // 调用打包器的 pack_nalu 方法将单个 NALU 打包成 RTP 数据包
            packer.pack_nalu(nalu).await?;
        } else {
            // 如果没有找到起始码，退出循环
            break;
        }
    }
    Ok(())
}

/// 函数用于获取当前系统时间
pub fn current_time() -> u64 {
    let duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);

    match duration {
        Ok(result) => (result.as_nanos() / 1000) as u64,
        _ => 0,
    }
}
